#include "frametiming.h"
#include "textrenderer.h"

FrameTiming* FrameTiming::singleton = 0;

FrameTiming::FrameTiming()
{
	singleton = this;
	tprev = -1;
	TextRenderer::getSingleton().addTextBox("framerateDisplay", "", 500, 40, 100, 20, Ogre::ColourValue::Green);
	FrameTiming::getSingleton()->addTimer("updateFramerateDisplay", 500000, updateFramerateDisplay, (void*)this);
}
FrameTiming::~FrameTiming()
{
	
}

FrameTiming::TimerInfo::TimerInfo(unsigned long period, void (*callback)(void*), void* data)
	: period(period), elapsed(0), data(data)
{
	this->callback = callback;
}

FrameTiming::TimerInfo::TimerInfo(const TimerInfo &timerInfo)
	: callback(timerInfo.callback), elapsed(timerInfo.elapsed), period(timerInfo.period), data(timerInfo.data)
{
}


/**
 * Sirve para saber el tiempo entre el frame actual y el anterior.
 * También actualiza los timers y llama a las funciones de callback
 * necesarias.
 * Ésta función debería ser llamada en cada frame.
 */
void FrameTiming::doFrameTiming()
{
	if(tprev == -1)
	{
		// Inicialización
		tprev = tcurrent = timer.getMicroseconds();
	}
	else
	{
		tprev = tcurrent;
		tcurrent = timer.getMicroseconds();
	}
	
	map<string, TimerInfo>::iterator it;
	for(it = timers.begin(); it != timers.end(); it++)
	{
		TimerInfo* timer = &((*it).second);
		timer->elapsed += (tcurrent - tprev);
		if(timer->elapsed > timer->period)
		{
			timer->elapsed = timer->elapsed % timer->period;
			(*timer->callback)(timer->data);
		}
	}
}

void FrameTiming::addTimer(string name, unsigned long period, void (*callback)(void*), void* data)
{
	timers[name] = TimerInfo(period, callback, data);
}

void FrameTiming::delTimer(string name)
{
	timers.erase(name);
}

/**
 * Calcula el tiempo entre el frame anterior y el actual.
 */
float FrameTiming::timeSinceLastFrame()
{
	// El 100.000 sirve para pasar de microsegundos a segundos
	return (tcurrent - tprev) / 1000000.0;
}

FrameTiming* FrameTiming::getSingleton()
{
	if(singleton == 0)
		singleton = new FrameTiming();
		
	return singleton;
}

void FrameTiming::updateFramerateDisplay(void *data)
{
	ostringstream ostream;
	
	FrameTiming* ft = reinterpret_cast<FrameTiming*>(data);
	
	ostream << "FrameRate: " << 1.0/ft->timeSinceLastFrame();
	TextRenderer::getSingleton().setText("framerateDisplay", ostream.str());
}
